package com.efun.center.http.config;

import com.alibaba.fastjson.JSONObject;
import com.efun.center.http.annotation.HttpHandler;
import com.efun.center.http.annotation.HttpService;
import com.efun.center.http.handler.HttpSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 方法调用器
 * 
 * @author hedongzhou
 *
 */
public class MethodInvoker {

    private final Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * 处理器
	 */
	protected HttpSupport handlerObject;

	/**
	 * 参数命名
	 */
	protected String[] paramKeys;

	/**
	 * 返回类型
	 */
	protected Class<?> returnType;

	/**
	 * 远程方法
	 */
	protected String method;

	/**
	 * 超时时间
	 */
	protected int timeout;

	/**
	 * 是否异步
	 */
	protected boolean isAsync;

	/**
	 * 是否忽略异常
	 */
	protected boolean ignoreErr;

    /**
     * 请求格式
     */
    protected String contentType;

	/**
	 * 配置生成
	 */
	protected ProjectLoader projectLoader;

	public MethodInvoker(ProjectLoader projectLoader, Method method) throws Exception {
		logger.debug("MethodInvoker creates method[" + method + "]");

		// 为了支持重载配置，所以这里不直接过去映射对象
		this.projectLoader = projectLoader;

		// 获取返回类型
		returnType = method.getReturnType();
        this.method = method.getName();

		HttpHandler handler = method.getAnnotation(HttpHandler.class);

		if (handler == null) {
			logger.error("Handler is necessary");
			throw new RuntimeException("Handler is necessary: " + method);
		}
		paramKeys = handler.params();
		timeout = handler.timeout();
		isAsync = handler.async();
		ignoreErr = handler.ignoreErr();
        contentType = handler.contentType().toString();

		Class<? extends HttpSupport> handlerClass = handler.type();

		// 获取处理器
		try {
			handlerObject = projectLoader.getHandler(handlerClass);

			logger.debug("Found the bean by handlerClass[" + handlerClass + "]");
		} catch (Exception e) {
			logger.debug("Cant not find the bean by handlerClass[" + handlerClass + "]");
		}

		if (handlerObject == null) {
			try {
				handlerObject = handlerClass.newInstance();

				logger.debug("New the bean by handlerClass[" + handlerClass + "]");
			} catch (Exception e) {
				logger.debug("handlerObject creates failed: " + e.getMessage());
				e.printStackTrace();
				throw e;
			}
		}
	}

	/**
	 * 调用
	 * 
	 * @param params
	 *            参数
	 * @return
	 */
	public Object invoke(Class<?> service, Object[] params) {
		Map<String, Object> paramMap = new HashMap<String, Object>();
		for (int i = 0; i < paramKeys.length && i < params.length; i++) {
			paramMap.put(paramKeys[i], params[i]);
		}

		ParamInfo paramInfo = new ParamInfo();
		String methodKey = service.getAnnotation(HttpService.class).project() + "." + method;
		paramInfo.setMethodMapper(projectLoader.getMethodMapper(methodKey));
		paramInfo.setParams(paramMap);
		paramInfo.setTimeout(timeout);
		paramInfo.setIgnoreErr(ignoreErr);
		paramInfo.setContentType(contentType);

		if (isAsync) {
			new Thread(new Runnable() {
				public void run() {
					handlerObject.deal(paramInfo);
				}
			}).start();

			return null;
		} else {
			// 处理
			String json = handlerObject.deal(paramInfo);
			
			// 根据返回类型，进行转换
			switch (returnType.getName()) {
				case "void":
					return null;
				case "java.lang.String":
					return json;
				default:
					return JSONObject.parseObject(json, returnType);
			}
		}
	}

}
